package com.sale.table.service.impl;

import com.sale.common.core.constant.CacheNames;
import com.sale.common.core.utils.StreamUtils;
import com.sale.common.core.utils.StringUtils;
import com.sale.common.mybatis.core.page.PageQuery;
import com.sale.common.redis.utils.CacheUtils;
import com.sale.storage.api.RemoteWarehouseReportService;
import com.sale.storage.api.dto.InvoicingReportDto;
import com.sale.storage.api.vo.InventoryBalanceVo;
import com.sale.system.api.RemoteUnitService;
import com.sale.system.api.domain.SysAuxiliary;
import com.sale.system.api.domain.SysAuxiliaryUnitDetail;
import com.sale.system.api.model.MaterialUnitDto;
import com.sale.table.domain.*;
import com.sale.table.domain.AfterCome;
import com.sale.table.domain.dto.SalesTotalDto;
import com.sale.table.domain.vo.*;
import com.sale.table.mapper.SaleOrderStatisticsMapper;
import com.sale.table.mapper.TableGoodsMapper;
import com.sale.table.service.ITableGoodsService;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 财务报表
 * @Date 23-09-14
 * @Author hl
 **/
@RequiredArgsConstructor
@Service
public class TableGoodsServiceImpl implements ITableGoodsService {

    private final TableGoodsMapper tableGoodsMapper;

    private final SaleOrderStatisticsMapper saleOrderStatisticsMapper;

    @DubboReference
    private RemoteUnitService remoteUnitService;

    @DubboReference
    RemoteWarehouseReportService remoteWarehouseReportService;

    /**
     * 往来单位一览表
     */
    @Override
    public List<GoodsCome> selectTableComeList(GoodsComeVo goodsComeVo) {
        List<GoodsCome> page = new ArrayList<>();
        if (goodsComeVo.getType() == 1) {
            // 查询所有客户
            List<GoodsClient> clientList = tableGoodsMapper.selectGoodsComeClient(goodsComeVo);
            //代表客户
            List<GoodsCome> pageClient = tableGoodsMapper.selectTableComeList(goodsComeVo);
            if (pageClient.size() == 0) {
                //代表在日期范围内没值 算期初余额
                pageClient = tableGoodsMapper.selectTablePeriodList(goodsComeVo);
            }
            //查看客户核销数据
            List<AfterCome> afterList = tableGoodsMapper.selectAfterComeList(goodsComeVo);
            Map<String, List<AfterCome>> afterMap = StreamUtils.groupByKey(afterList, AfterCome::getCode);
            Map<String, List<GoodsCome>> listMap = StreamUtils.groupByKey(pageClient, GoodsCome::getClientCode);
            for (GoodsClient client :
                clientList) {
                List<AfterCome> list2 = afterMap.get(client.getClientCode());
                BigDecimal bb = new BigDecimal(0);
                if(list2!=null){
                    for (AfterCome item: list2) {
                        bb = bb.add(item.getAmount());
                    }
                }
                List<GoodsCome> list1 = listMap.get(client.getClientCode());
                if (list1 != null) {
                    GoodsCome come = list1.get(0);
                    come.setClientCode(client.getClientCode());
                    come.setClientName(client.getClientName());
                    come.setTypeName(client.getTypeName());
                    if (come.getAmount() != null) {
                        come.setBalanceAmount(new BigDecimal(0));
                        come.setClosedAmount(come.getAmount().subtract(come.getPackageDiscount()).add(bb));
                        come.setBalanceOfAccounts(come.getClosedAmount().subtract(come.getCollectionAmount()));
                    }
                    page.add(come);
                }else{
                    GoodsCome come = new GoodsCome();
                    come.setClientCode(client.getClientCode());
                    come.setClientName(client.getClientName());
                    come.setTypeName(client.getTypeName());
                    come.setClosedAmount(bb);
                    page.add(come);
                }
            }
        } else {
            //代表供应商
            // 查询所有供应商
            List<GoodsSupplier> supplierList = tableGoodsMapper.selectGoodsComeSupplier(goodsComeVo);
            List<GoodsCome> pageCome = tableGoodsMapper.selectTableSupplierList(goodsComeVo);
            if (pageCome.size() == 0) {
                //代表在日期范围内没值 算期初余额
                pageCome = tableGoodsMapper.selectTablePeriodList2(goodsComeVo);
            }
            //查看供应商核销数据
            List<AfterCome> afterList2 = tableGoodsMapper.selectAfterComeList2(goodsComeVo);
            Map<String, List<AfterCome>> afterMap = StreamUtils.groupByKey(afterList2, AfterCome::getCode);
            Map<String, List<GoodsCome>> listMap = StreamUtils.groupByKey(pageCome, GoodsCome::getClientCode);
            for (GoodsSupplier supplier :
                supplierList) {
                List<AfterCome> list2 = afterMap.get(supplier.getSupplierCode());
                BigDecimal bb = new BigDecimal(0);
                if(list2!=null){
                    for (AfterCome item: list2) {
                        bb = bb.add(item.getAmount());
                    }
                }
                List<GoodsCome> list1 = listMap.get(supplier.getSupplierCode());
                if (list1 != null) {
                    GoodsCome come = list1.get(0);
                    come.setClientCode(supplier.getSupplierCode());
                    come.setClientName(supplier.getSupplierName());
                    come.setTypeName(supplier.getTypeName());
                    if (come.getAmount() != null) {
                        come.setBalanceAmount(new BigDecimal(0));
                        come.setClosedAmount(come.getAmount().subtract(come.getPackageDiscount()).add(bb));
                        come.setBalanceOfAccounts(come.getClosedAmount().subtract(come.getCollectionAmount()));
                    }
                    page.add(come);
                }else{
                    GoodsCome come = new GoodsCome();
                    come.setClientCode(supplier.getSupplierCode());
                    come.setClientName(supplier.getSupplierName());
                    come.setTypeName(supplier.getTypeName());
                    come.setClosedAmount(bb);
                    page.add(come);
                }
            }
        }
        return page;
    }

    /**
     * 客户对账单
     */
    @Override
    public List<GoodsReconciliation> selectClientRightList(GoodsReconciliationVo goodsReconciliationVo) {
        List<GoodsReconciliation> list = tableGoodsMapper.selectClientRightList(goodsReconciliationVo);
        List<GoodsReconciliation> list1 = tableGoodsMapper.selectGoodsRightList(goodsReconciliationVo);
        list.addAll(list1);
        //查询日期前的数据
        return share(list, tableGoodsMapper.selectThePeriod(goodsReconciliationVo));
    }

    /**
     * 供应商对账单
     */
    @Override
    public List<GoodsReconciliation> selectSupplierRightList(GoodsSupplierVo goodsSupplierVo) {
        List<GoodsReconciliation> list = tableGoodsMapper.selectSupplierRightList(goodsSupplierVo);
        List<GoodsReconciliation> list1 = tableGoodsMapper.selectPaymentRightList(goodsSupplierVo);
        list.addAll(list1);
        return share(list, tableGoodsMapper.selectPaymentPeriod(goodsSupplierVo));
    }

    /**
     * 共用方法
     */
    private List<GoodsReconciliation> share(List<GoodsReconciliation> list, Double au) {
        //拆分核销单数据
        //List<GoodsReconciliation> list1 = tableGoodsMapper.selectCancelAfterI


        Collections.sort(list, new Comparator<GoodsReconciliation>() {
            @Override
            public int compare(GoodsReconciliation o1, GoodsReconciliation o2) {
                return o1.getTime().compareTo(o2.getTime());
            }
        });
        BigDecimal b1 = BigDecimal.valueOf(au);
        for (GoodsReconciliation recon :
            list) {
            recon.setBalanceOfAccounts(recon.getClosedAmount().subtract(recon.getCollectionAmount()).add(b1));
        }
        GoodsReconciliation reconciliation = new GoodsReconciliation();
        reconciliation.setDoc("期初余额");
        reconciliation.setType("期初");
        reconciliation.setBalanceOfAccounts(b1);
        list.add(reconciliation);
        Collections.swap(list, list.size() - 1, 0);
        for (int i = 1; i < list.size(); i++) {
            GoodsReconciliation o2 = list.get(i);
            GoodsReconciliation o3 = list.get(i - 1);
            //应收款余额
            BigDecimal b2 = o3.getBalanceOfAccounts();
            String type3 = o2.getType();
            if (type3.equals("销售退货单") || type3.equals("核销(转出)") || type3.equals("其他支出单")) {
                o2.setBalanceOfAccounts(b2.add(o2.getCollectionAmount()));
            } else {
                //收款
                o2.setBalanceOfAccounts(b2.subtract(o2.getCollectionAmount()));
            }
        }
        return list;
    }


    /**
     * 应收账款明细表
     */
    @Override
    public List<GoodsReceivable> selectReceivableList(GoodsReceivableVo goodsReceivableVo) {
        // 查询所有客户
        List<GoodsClient> clientList = tableGoodsMapper.selectGoodsClient(goodsReceivableVo);
        // 查询 (销售发货单、销售退货单、核销单、收款单)
        List<GoodsReceivable> receivableList = tableGoodsMapper.selectReceivableList(goodsReceivableVo);
        List<GoodsReceivable> goodsList = tableGoodsMapper.selectGoodsList(goodsReceivableVo);
        receivableList.addAll(goodsList);
        Map<String, List<GoodsReceivable>> listMap = StreamUtils.groupByKey(receivableList, GoodsReceivable::getClientCode);
        List<GoodsReceivable> list = new ArrayList<GoodsReceivable>();
        for (GoodsClient goods :
            clientList) {
            List<GoodsReceivable> list1 = listMap.get(goods.getClientCode());
            if (list1 != null) {
                String name = goods.getClientName();
                String typeName = goods.getTypeName();
                Collections.sort(list1, new Comparator<GoodsReceivable>() {
                    @Override
                    public int compare(GoodsReceivable o1, GoodsReceivable o2) {
                        return o1.getTime().compareTo(o2.getTime());
                    }
                });
                GoodsReceivable receivable = new GoodsReceivable();
                receivable.setClientCode(goods.getClientCode());
                receivable.setClientName(name);
                receivable.setTypeName(typeName);
                receivable.setClosedBalance(goods.getAugmentClosed());
                list1.add(receivable);
                Collections.swap(list1, list1.size() - 1, 0);
                // list.addAll(list1);
                for (int i = 1; i < list1.size(); i++) {
                    GoodsReceivable o2 = list1.get(i);
                    GoodsReceivable o3 = list1.get(i - 1);
                    o2.setClientName(name);
                    o2.setTypeName(typeName);
                    //应收款余额
                    BigDecimal b1 = o3.getClosedBalance();
                    String type3 = o2.getType();
                    if (type3.equals("销售发货") || type3.equals("销售退货") ||  type3.equals("核销(转出)")) {
                        o2.setClosedBalance(b1.add(o2.getAugmentClosed()));
                    } else {
                        //收款
                        o2.setClosedBalance(b1.subtract(o2.getAugmentAdvance()));
                    }
                }
                list.addAll(list1);
            }
        }
        return list;
    }


    /**
     * 应付账款明细表
     */
    @Override
    public List<GoodsCopeWith> selectCopeWithList(GoodsCopeWithVo goodsCopeWithVo) {
        // 查询所有供应商
        List<GoodsSupplier> supplierList = tableGoodsMapper.selectGoodsSupplier(goodsCopeWithVo);
        // 查询 (采购入库单、采购退货单、核销单、付款单)
        List<GoodsCopeWith> receivableList = tableGoodsMapper.selectCopeWithList(goodsCopeWithVo);
        List<GoodsCopeWith> goodsList = tableGoodsMapper.selectGoodsPaymentList(goodsCopeWithVo);
        receivableList.addAll(goodsList);
        Map<String, List<GoodsCopeWith>> listMap = StreamUtils.groupByKey(receivableList, GoodsCopeWith::getSupplierCode);
        List<GoodsCopeWith> list = new ArrayList<GoodsCopeWith>();
        for (GoodsSupplier goods :
            supplierList) {
            List<GoodsCopeWith> list1 = listMap.get(goods.getSupplierCode());
            if (list1 != null) {
                String name = goods.getSupplierName();
                String typeName = goods.getTypeName();
                Collections.sort(list1, new Comparator<GoodsCopeWith>() {
                    @Override
                    public int compare(GoodsCopeWith o1, GoodsCopeWith o2) {
                        return o1.getTime().compareTo(o2.getTime());
                    }
                });
                GoodsCopeWith receivable = new GoodsCopeWith();
                receivable.setSupplierCode(goods.getSupplierCode());
                receivable.setSupplierName(name);
                receivable.setTypeName(typeName);
                receivable.setClosedBalance(goods.getAugmentClosed());
                list1.add(receivable);
                Collections.swap(list1, list1.size() - 1, 0);
                // list.addAll(list1);
                for (int i = 1; i < list1.size(); i++) {
                    GoodsCopeWith o2 = list1.get(i);
                    GoodsCopeWith o3 = list1.get(i - 1);
                    o2.setSupplierName(name);
                    o2.setTypeName(typeName);
                    //应收款余额
                    BigDecimal b1 = o3.getClosedBalance();
                    if (o2.getType().equals("采购入库单") || o2.getType().equals("采购退货单")) {
                        o2.setClosedBalance(b1.add(o2.getAugmentClosed()));
                    } else {
                        //收款
                        o2.setClosedBalance(b1.subtract(o2.getAugmentAdvance()));
                    }
                }
                list.addAll(list1);
            }
        }
        return list;
    }

    /**
     * 金额报表
     */
    @Override
    public List<GoodsAmount> selectAmountList(GoodsAmountVo goodsAmountVo) {
        List<GoodsAmount> list = tableGoodsMapper.selectSysList(goodsAmountVo);
        List<GoodsAmount> list1 = tableGoodsMapper.selectAmountList(goodsAmountVo);
        List<PullDown> pullList1 = tableGoodsMapper.selectPayerName();
        Map<String, String> map1 = pullList1.stream().collect(Collectors.toMap(PullDown::getStr, PullDown::getPair));
        Map<String, List<GoodsAmount>> listMap = StreamUtils.groupByKey(list1, GoodsAmount::getAccountId);
        List<GoodsAmount> list3 = new ArrayList<GoodsAmount>();
        for (GoodsAmount amount :
            list) {
            BigDecimal b1 = amount.getBalance();
            String code = amount.getAccountCode();
            String name = amount.getAccountName();
            List<GoodsAmount> list2 = listMap.get(amount.getAccountId());
            if (list2 != null) {
                Collections.sort(list2, new Comparator<GoodsAmount>() {
                    @Override
                    public int compare(GoodsAmount o1, GoodsAmount o2) {
                        return o1.getTime().compareTo(o2.getTime());
                    }
                });
                for (int i = 0; i < list2.size(); i++) {
                    GoodsAmount m1 = list2.get(i);
                    m1.setAccountCode(code);
                    m1.setAccountName(name);
                    String type = m1.getType();
                    if (type.equals("收款") || type.equals("其他收入") || type.equals("转账(转入)")) {
                        m1.setBalance(b1.add(m1.getIncome()));
                    } else {
                        m1.setBalance(b1.subtract(m1.getIncome()));
                    }
                    m1.setPayerName(map1.get(m1.getPayerName()));
                    if (StringUtils.isNotEmpty(m1.getComeUnit())) {
                        m1.setComeUnit(map1.get(m1.getComeUnit()));
                    }
                }
                GoodsAmount amount2 = new GoodsAmount();
                amount2.setAccountCode(code);
                amount2.setAccountName(name);
                amount2.setBalance(b1);
                list3.addAll(list2);
                Collections.swap(list3, list3.size() - 1, 0);
            }
        }

        return list3;
    }

    /**
     * 利润表
     */
    @Override
    public GoodsProfit selectProfitList(GoodsProfitVo goodsProfitVo) {
        GoodsProfit profit = tableGoodsMapper.selectProfitList(goodsProfitVo);
        SalesTotalVo vo = new SalesTotalVo();
        vo.setBeginTime(goodsProfitVo.getBeginTime());
        vo.setEndTime(goodsProfitVo.getEndTime());
        vo.setStatisticalMethod(1);
        PageQuery page = new PageQuery();
        page.setPageNum(1000000);
        page.setPageSize(1);
        BigDecimal b2 = new BigDecimal(0);
        InventoryBalanceVo inventoryBalanceVo = new InventoryBalanceVo();
        List<InvoicingReportDto> invoicingReport = remoteWarehouseReportService.getInvoicingReport(inventoryBalanceVo);
        //根据物料编码转为map
        Map<String, String> invoicingReportMap = invoicingReport.stream()
            .filter(entity -> entity.getWodDocNum() != null && entity.getBalancePrice() != null)
            .collect(Collectors.toMap(InvoicingReportDto::getWodDocNum, InvoicingReportDto::getBalancePrice));


        List<SalesTotalDto> records = saleOrderStatisticsMapper.getSalesTotalList(vo);
//        List<SalesTotalDto> records = salesTotalList.getRecords();
        for (SalesTotalDto entity : records) {
            //辅助属性
            List<SysAuxiliary> statsArray = CacheUtils.get(CacheNames.SYS_GINSENG + "_" + entity.getTenantId(), String.valueOf(entity.getMaterialId()));
            entity.setAuxiliaryAttribute(statsArray);
            //类别
            if ("1".equals(entity.getCategory())) {
                entity.setCategoryDict("原料");
            } else {
                entity.setCategoryDict("成品");
            }
            MaterialUnitDto unitByCode = remoteUnitService.getUnitByCode(entity.getMaterialCode());
            //多单位
            entity.setMaterialMoreUnit(unitByCode.getAuxiliaryUnit());
            //多单位数量
            entity.setMaterialMoreUnitNumber(getMoreUnit(String.valueOf(entity.getMaterialTotal()), unitByCode));
            //单位
            entity.setUnitDict(unitByCode.getUnitName());
            //销售成本 = 单位数量*结存单价；(结存单价从进销存统计表中获取)
            String s = invoicingReportMap.get(entity.getDocumentNumber());
            if (s != null) {
                BigDecimal multiply = new BigDecimal(entity.getMaterialTotal()).multiply(new BigDecimal(s));
                b2.add(multiply);
            }
        }
        profit.setSaleCost(b2);
        profit.setOperatingProfit(profit.getSaleAmount().subtract(profit.getCollectionDiscount()).subtract(b2).add(profit.getPaymentDiscount()));
        profit.setOtherBusiness(profit.getOtherIncome().add(profit.getOtherExpenditure()));
        profit.setNetProfit(profit.getOtherBusiness().add(profit.getOperatingProfit()));
        profit.setDiscLoss(new BigDecimal(0));
        return profit;
    }


    /**
     * 获取多单位数量
     *
     * @param materialTotal
     * @param unitByCode
     * @return
     */
    public String getMoreUnit(String materialTotal, MaterialUnitDto unitByCode) {
        String moreUnit = "";

        String num = materialTotal;

        List<SysAuxiliaryUnitDetail> list = unitByCode.getList();
        if (list != null) {
            for (SysAuxiliaryUnitDetail sysAuxiliaryUnitDetail : list) {
                String unitQuantity = sysAuxiliaryUnitDetail.getUnitQuantity();
                BigDecimal number1 = new BigDecimal(num);
                BigDecimal number2 = new BigDecimal(unitQuantity);
                BigDecimal[] bigDecimals = number1.divideAndRemainder(number2);
                // 数组的第一个值为商，第二个值为余数
                String discuss = bigDecimals[0].toString();
                String remainder = bigDecimals[1].toString();

                //如果直接被整除说明刚好满足当前最大单位
                if ("0".equals(remainder)) {
                    moreUnit = moreUnit + discuss + sysAuxiliaryUnitDetail.getUnitName();
                    break;
                } else {
                    if ("0".equals(discuss)) {
                        continue;
                    }
                    //没有被整除
                    moreUnit = moreUnit + discuss + sysAuxiliaryUnitDetail.getUnitName();
                    //修改num的值为当前的余数
                    num = remainder;
                    if (sysAuxiliaryUnitDetail == list.get(list.size() - 1)) {
                        moreUnit = moreUnit + remainder + unitByCode.getUnitName();
                    }
                }
            }
        }

        if ("".equals(moreUnit)) {
            moreUnit = materialTotal + "" + unitByCode.getUnitName();
        }
        return moreUnit;

    }

}
